package com.fabiodocarmo.calendario.dao;

import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import com.fabiodocarmo.calendario.Calendario;
import com.fabiodocarmo.calendario.beans.Bean;
import com.fabiodocarmo.calendario.dao.util.DataAccessLayerException;
import com.fabiodocarmo.calendario.dao.util.HibernateFactory;


/**
 * Classe abstrata topo da hierarquia de DAO's (Data Access Object).
 * @author Taciano Morais Silva
* @version 13/03/2009, 15h25m, Fábio do Carmo - fabioducarmo@gmail.com
 * @since 13/03/2009, 11h28m
 */
public abstract class AbstractDao<T extends Bean> {

    protected Session session;
    protected Transaction tx;
    private Calendario calendario;

    /**
     * @throws DataAccessLayerException
     */
    public AbstractDao() throws DataAccessLayerException {
        HibernateFactory.buildIfNeeded();
    }

    /**
     * @param calenadario
     * @throws DataAccessLayerException
     */
    public AbstractDao(Calendario calendario) throws DataAccessLayerException {
        this();
        this.calendario = calendario;
    }

    /**
     * @param obj
     * @throws DataAccessLayerException
     */
    protected void saveOrUpdate(T obj) throws DataAccessLayerException {
        try {
            startOperation();
            session.saveOrUpdate(obj);
            tx.commit();
        } catch (HibernateException e) {
            handleException(e);
        } finally {
            HibernateFactory.close(session);
        }
    }

    /**
     * @param obj
     * @throws DataAccessLayerException
     */
    protected void delete(T obj) throws DataAccessLayerException {
        try {
            startOperation();
            session.delete(obj);
            tx.commit();
        } catch (HibernateException e) {
            handleException(e);
        } finally {
            HibernateFactory.close(session);
        }
    }

    /**
     * @param clazz
     * @param id
     * @throws DataAccessLayerException
     */
    protected void delete(Class<T> clazz, Integer id) throws DataAccessLayerException {
        Object obj = null;
        try {
            startOperation();
            obj = session.load(clazz, id);
            session.delete(obj);
            tx.commit();
        } catch (HibernateException e) {
            handleException(e);
        } finally {
            HibernateFactory.close(session);
        }
    }

    /**
     * @param clazz
     * @param id
     * @return
     * @throws DataAccessLayerException
     */
    protected Object find(Class<T> clazz, Integer id) throws DataAccessLayerException {
        Object obj = null;
        try {
            startOperation();
            obj = session.load(clazz, id);
            tx.commit();
        } catch (HibernateException e) {
            handleException(e);
        } finally {
            //HibernateFactory.close(session);
            //if (cesuWeb != null) {
                calendario.addSessaoHibernate(session);
            //}
        }
        return obj;
    }

    /**
     * @param clazz
     * @return
     * @throws DataAccessLayerException
     */
    @SuppressWarnings("unchecked")
    protected List<T> findAll(Class<T> clazz) throws DataAccessLayerException {
        List<T> objects = null;
        try {
            startOperation();
            Query query = session.createQuery("from " + clazz.getName());
            objects = query.list();
            tx.commit();
        } catch (HibernateException e) {
            handleException(e);
        } finally {
            HibernateFactory.close(session);
        }
        return objects;
    }

    /**
     * @throws HibernateException
     */
    protected void startOperation() throws HibernateException {
        session = HibernateFactory.openSession();
        tx = session.beginTransaction();
    }

    /**
     * @param e
     * @throws DataAccessLayerException
     */
    protected void handleException(HibernateException e) throws DataAccessLayerException {
        HibernateFactory.rollback(tx);
        throw new DataAccessLayerException(e);
    }

}
